home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2007 December
/
PCWKCD1207B.iso
/
Blogowanie poza sfera
/
Flock 1.0 beta
/
flock-1.0RC3.en-US.win32.exe
/
flock
/
components
/
flockMetricsService.js
< prev
next >
Wrap
Text File
|
2007-10-18
|
20KB
|
740 lines
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2007
// http://flock.com
//
// This file may be used under the terms of of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
const MS_CONTRACTID = "@flock.com/metrics-service;1";
const MS_CLASSID = Components.ID("{bc1358fa-6e36-4d0d-a401-b0b02111114c}");
const MS_CLASSNAME = "Flock Metrics Service";
const ENABLED_BY_DEFAULT = true;
const STORE_FILENAME = "mstore.sqlite";
const OLD_STORE_FILENAME = "mstore.js";
const LOGGING_URL = "http://metrics.flock.com/anonusage.php";
const PREF_FLOCK_METRICS_ENABLED = "flock.metrics.enabled";
const PREF_FLOCK_METRICS_INTERVAL = "flock.metrics.interval";
const DEFAULT_METRICS_INTERVAL = 86400;
const PREF_FLOCK_FIRSTRUN_UUID = "flock.firstrun.uuid";
const PREF_GENERAL_USERAGENT_EDITION = "general.useragent.edition";
const PREF_GENERAL_USERAGENT_LOCALE = "general.useragent.locale";
const PREF_DEFAULT_SEARCH_ENGINE = "browser.search.selectedEngine";
const PREF_DEFAULT_ENGINE_NAME = "browser.search.defaultenginename";
const PREF_BROWSER_STARTUP_HOMEPAGE = "browser.startup.homepage";
const PREF_FEED_SELECTED_ACTION = "browser.feeds.handler";
const PREF_FLOCK_FIRST_RUN_BIGDATE = "flock.first_run.bigDate";
const URI_BRAND_PROPERTIES = "chrome://branding/locale/brand.properties";
const MYWORLD_URL = "about:myworld";
const HTTP_CODE_OK = 200;
const IS_AUTHENTICATED_RSC = "http://flock.com/rdf#isAuthenticated";
const IS_TRANSIENT_RSC = "http://flock.com/rdf#isTransient";
const CC = Components.classes;
const CI = Components.interfaces;
const CR = Components.results;
const CU = Components.utils;
CU.import("resource:///modules/FlockXPCOMUtils.jsm");
CU.import("resource://gre/modules/JSON.jsm");
CU.import("resource:///modules/FlockCryptoHash.jsm");
var gApp = null;
var gPref = null;
var gABI = null;
var gOSVersion = null;
function getObserverService() {
return CC["@mozilla.org/observer-service;1"]
.getService(CI.nsIObserverService);
}
function getCharPref(aPrefName, aDefaultValue) {
if (gPref.getPrefType(aPrefName) == CI.nsIPrefBranch.PREF_STRING) {
return gPref.getCharPref(aPrefName);
} else {
return aDefaultValue;
}
}
function getIntPref(aPrefName, aDefaultValue) {
if (gPref.getPrefType(aPrefName) == CI.nsIPrefBranch.PREF_INT) {
return gPref.getIntPref(aPrefName);
} else {
return aDefaultValue;
}
}
function getBoolPref(aPrefName, aDefaultValue) {
if (gPref.getPrefType(aPrefName) == CI.nsIPrefBranch.PREF_BOOL) {
return gPref.getBoolPref(aPrefName);
} else {
return aDefaultValue;
}
}
function createStatement(aDBConn, aSQL) {
var stmt = aDBConn.createStatement(aSQL);
var wrapper = CC["@mozilla.org/storage/statement-wrapper;1"]
.createInstance(CI.mozIStorageStatementWrapper);
wrapper.initialize(stmt);
return wrapper;
}
function MetricsService() {
gApp = CC["@mozilla.org/xre/app-info;1"]
.getService(CI.nsIXULAppInfo)
.QueryInterface(CI.nsIXULRuntime);
gPref = CC["@mozilla.org/preferences-service;1"]
.getService(CI.nsIPrefBranch2)
try {
gABI = gApp.XPCOMABI;
var macutils = CC["@mozilla.org/xpcom/mac-utils;1"];
if (macutils) {
if (macutils.getService(CI.nsIMacUtils).isUniversalBinary) {
gABI = "Universal-gcc3";
}
}
} catch (ex) {
}
try {
var sysInfo = CC["@mozilla.org/system-info;1"]
.getService(CI.nsIPropertyBag2);
gOSVersion = sysInfo.getProperty("name") + " " +
sysInfo.getProperty("version");
} catch (ex) {
}
var obs = getObserverService();
obs.addObserver(this, "flock-data-ready", false);
obs.addObserver(this, "xpcom-shutdown", false);
this.observe(null, "nsPref:changed", PREF_FLOCK_METRICS_ENABLED);
}
MetricsService.prototype = new FlockXPCOMUtils.genericComponent(
MS_CLASSNAME,
MS_CLASSID,
MS_CONTRACTID,
MetricsService,
CI.nsIClassInfo.SINGLETON,
[
CI.flockIMetricsService,
CI.flockIRDFObserver,
CI.nsITimerCallback,
CI.nsIObserver
]
);
MetricsService.prototype._xpcom_categories = [
{ category: "flock-startup", service: true }
];
MetricsService.prototype._start =
function MS__start() {
this._logger = CC["@flock.com/logger;1"].createInstance(CI.flockILogger);
this._logger.init("metrics");
this._logger.info("starting up...");
this._deleteOldStore();
this.getUserUUID();
this._coop = CC["@flock.com/singleton;1"]
.getService(CI.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
gPref.addObserver(PREF_FLOCK_METRICS_ENABLED, this, false);
this.observe(null, "nsPref:changed", PREF_FLOCK_METRICS_ENABLED);
this._watchLoginEvents();
this.report("Browser-Start");
gPref.addObserver(PREF_DEFAULT_SEARCH_ENGINE, this, false);
gPref.addObserver(PREF_BROWSER_STARTUP_HOMEPAGE, this, false);
gPref.addObserver(PREF_FEED_SELECTED_ACTION, this, false);
var tm = CC["@mozilla.org/updates/timer-manager;1"]
.getService(CI.nsIUpdateTimerManager);
var interval = getIntPref(PREF_FLOCK_METRICS_INTERVAL,
DEFAULT_METRICS_INTERVAL);
tm.registerTimer("background-metrics-timer", this, interval);
}
MetricsService.prototype._shutdown =
function MS__shutdown() {
gApp = null;
gPref = null;
}
MetricsService.prototype.notify =
function MS_notify(aTimer) {
this._sendReport();
}
MetricsService.prototype._configure =
function MS__configure() {
this._enabled = getBoolPref(PREF_FLOCK_METRICS_ENABLED, ENABLED_BY_DEFAULT);
if (this._enabled) {
this._createStore();
} else {
this._deleteStore();
}
}
MetricsService.prototype._prefChanged =
function MS__prefChanged(aPref) {
switch (aPref) {
case PREF_DEFAULT_SEARCH_ENGINE:
this._reportDefaultSearchEngine();
break;
case PREF_BROWSER_STARTUP_HOMEPAGE:
this._reportMyWorldStartPage();
break;
case PREF_FEED_SELECTED_ACTION:
this._reportFeedReader();
break;
case PREF_FLOCK_METRICS_ENABLED:
this._configure();
break;
}
}
MetricsService.prototype.observe =
function MS_observe(aSubject, aTopic, aState) {
var obs = getObserverService();
switch (aTopic) {
case "flock-data-ready":
obs.removeObserver(this, "flock-data-ready");
this._start();
break;
case "xpcom-shutdown":
obs.removeObserver(this, "xpcom-shutdown");
this._shutdown();
break;
case "nsPref:changed":
this._prefChanged(aState);
break;
}
}
MetricsService.prototype._getProfileFile =
function MS__getProfileFile(aFileName) {
var file = CC["@mozilla.org/file/directory_service;1"]
.getService(CI.nsIProperties)
.get("ProfD", CI.nsILocalFile);
file.append(aFileName);
return file;
}
MetricsService.prototype._deleteOldStore =
function MS__deleteOldStore() {
var oldFile = this._getProfileFile(OLD_STORE_FILENAME);
try {
oldFile.remove(false);
} catch (ex) {
}
}
MetricsService.prototype._getMetricsDBFile =
function MS__getMetricsDBFile() {
return this._getProfileFile(STORE_FILENAME);
}
MetricsService.prototype._createStore =
function MS__createStore() {
var dbfile = this._getMetricsDBFile();
var storageService = CC["@mozilla.org/storage/service;1"]
.getService(CI.mozIStorageService);
this._DBConn = storageService.openDatabase(dbfile);
var schema = "key TEXT, value TEXT, type TEXT, time NUMBER";
var alreadyCreated = this._DBConn.tableExists("metrics");
if (!alreadyCreated) {
try {
this._DBConn.createTable("metrics", schema);
} catch (ex) {
this._DBConn = null;
this._enabled = false;
return;
}
}
this._insertEvent = createStatement(this._DBConn,
"INSERT INTO metrics (key, value, type, time) " +
"VALUES (:key, :value, :type, :time)");
this._getEvents = createStatement(this._DBConn,
"SELECT * FROM metrics WHERE time <= :time");
this._deleteEvents = createStatement(this._DBConn,
"DELETE FROM metrics WHERE time <= :time");
if (!alreadyCreated) {
this._fillPrefInfo();
}
}
MetricsService.prototype._deleteStore =
function MS__deleteStore() {
this._DBConn = null;
var dbfile = this._getMetricsDBFile();
try {
dbfile.remove(false);
} catch (ex) {
}
}
MetricsService.prototype._expireStore =
function MS__expireStore(aExpire) {
if (!aExpire) {
return;
}
var stmt = this._deleteEvents;
stmt.reset();
stmt.params.time = aExpire;
stmt.step();
}
MetricsService.prototype.getUserUUID =
function MS_getUserUUID() {
var currentUUID = getCharPref(PREF_FLOCK_FIRSTRUN_UUID);
if (!currentUUID) {
var uuidGen = CC["@mozilla.org/uuid-generator;1"]
.createInstance(CI.nsIUUIDGenerator);
var uuid;
try {
uuid = uuidGen.generateUUID();
} catch (ex) {
// Doh, not enough randomness, we'll try again in the future
return "0";
}
currentUUID = String(uuid).replace(/[{}]/g, "");
gPref.setCharPref(PREF_FLOCK_FIRSTRUN_UUID, currentUUID);
}
return currentUUID;
}
MetricsService.prototype._getBaseInfo =
function MS__getBaseInfo() {
var sbs = CC["@mozilla.org/intl/stringbundle;1"]
.getService(CI.nsIStringBundleService);
var bundle = sbs.createBundle(URI_BRAND_PROPERTIES);
var product = bundle.GetStringFromName("brandShortName");
var edition = getCharPref(PREF_GENERAL_USERAGENT_EDITION, "");
var uuid = this.getUserUUID();
var locale;
try {
locale = gPref.getComplexValue(PREF_GENERAL_USERAGENT_LOCALE,
nsIPrefLocalizedString).data;
} catch (ex) {
locale = getCharPref(PREF_GENERAL_USERAGENT_LOCALE);
}
var platform = gApp.OS + "_" + gABI;
var defaultBrowser;
try {
if (CC["@mozilla.org/browser/shell-service;1"]
.getService(CI.nsIShellService)
.isDefaultBrowser(false))
{
defaultBrowser = "true";
} else {
defaultBrowser = "false";
}
} catch (ex) {
defaultBrowser = "error";
}
var info = { "Browser-Product": product,
"Browser-Version": gApp.version,
"Browser-BuildID": gApp.appBuildID,
"Browser-Edition": edition,
"Browser-Locale": locale,
"Browser-Platform": platform,
"Browser-OSVersion": gOSVersion,
"Browser-MetricsEnabled": this._enabled,
"User-UUID": uuid,
"Browser-ClientTime": null,
"Browser-DefaultBrowser": defaultBrowser
};
var oldFirstRun = getCharPref(PREF_FLOCK_FIRST_RUN_BIGDATE);
if (oldFirstRun) {
info["User-FirstRun"] = oldFirstRun;
}
return info;
}
MetricsService.prototype._getFriendCounts =
function MS__reportFriendCounts() {
var friendCounts = [];
var catMgr = CC["@mozilla.org/categorymanager;1"]
.getService(CI.nsICategoryManager);
var svcEnum = catMgr.enumerateCategory("flockWebService");
while (svcEnum.hasMoreElements()) {
var entry = svcEnum.getNext().QueryInterface(CI.nsISupportsCString);
if (entry) {
var contractID = catMgr.getCategoryEntry("flockWebService", entry.data);
var svc = CC[contractID].getService(CI.flockIWebService);
if (svc instanceof CI.flockISocialWebService) {
var accounts = svc.getAccounts();
while (accounts.hasMoreElements()) {
var account = accounts.getNext()
.QueryInterface(CI.flockISocialWebServiceAccount);
friendCounts.push({service: svc.shortName,
account: FlockCryptoHash.md5(account.urn),
count: account.getFriendCount()});
}
}
}
}
return friendCounts;
}
MetricsService.prototype._fillPrefInfo =
function MS__fillPrefInfo() {
this._reportDefaultSearchEngine();
this._reportMyWorldStartPage();
this._reportFeedReader();
}
MetricsService.prototype._reportDefaultSearchEngine =
function MS__reportDefaultSearchEngine() {
var defaultEngine;
try {
defaultEngine = gPref.getCharPref(PREF_DEFAULT_SEARCH_ENGINE);
} catch (ex) {
defaultEngine = gPref.getComplexValue(PREF_DEFAULT_ENGINE_NAME,
CI.nsIPrefLocalizedString).data;
}
if (!defaultEngine)
defaultEngine = "";
this.report("SearchBox-DefaultSearchEngine", defaultEngine);
}
MetricsService.prototype._reportMyWorldStartPage =
function MS__reportMyWorldStartPage() {
var startPageHasMyWorld = false;
try {
var startPage = gPref.getComplexValue(PREF_BROWSER_STARTUP_HOMEPAGE,
CI.nsIPrefLocalizedString).data;
var startPages = startPage.split("|");
for each (var url in startPages) {
// Trim leading/trailing whitespace from URL
url = url.replace(/(^\s+)|(\s+$)/g, "");
if (url == MYWORLD_URL) {
startPageHasMyWorld = true;
break;
}
}
} catch (ex) {
}
this.report("Browser-MyWorldIsHomePage", startPageHasMyWorld);
}
MetricsService.prototype._reportFeedReader =
function MS__reportFeedReader() {
var feedReader, action = getCharPref(PREF_FEED_SELECTED_ACTION);
switch (action) {
case "ask":
feedReader = "news";
break;
case "bookmarks":
feedReader = "livemarks";
break;
default:
feedReader = "other";
break;
}
this.report("Feeds-DefaultNewsReader", feedReader);
}
MetricsService.prototype._watchLoginEvents =
function MS__watchLoginEvents() {
const RDFS = CC["@mozilla.org/rdf/rdf-service;1"]
.getService(CI.nsIRDFService);
var faves = RDFS.GetDataSource("rdf:flock-favorites");
faves.QueryInterface(CI.flockIRDFObservable);
faves.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE, null,
RDFS.GetResource(IS_AUTHENTICATED_RSC),
null, this);
faves.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE, null,
RDFS.GetResource(IS_TRANSIENT_RSC),
null, this);
}
MetricsService.prototype.rdfChanged =
function MS_rdfChanged(aDS, aType, aSource, aPredicate, aTarget, aOldTarget) {
if (aTarget instanceof CI.nsIRDFLiteral) {
var account = this._coop.get_from_resource(aSource);
if (aPredicate.ValueUTF8 == IS_AUTHENTICATED_RSC) {
if (account.isAuthenticated) {
this.report("Account-Login", account.serviceId);
} else {
this.report("Account-Logout", account.serviceId);
}
} else if (aPredicate.ValueUTF8 == IS_TRANSIENT_RSC) {
if (!account.isTransient) {
// The isTransient flag has changed. Please note that this will
// only ever change from "true" to "false"; when the user opts to
// "keep" the service. This means that we have to detect that the
// user opted to "FORGET" The service we have to detect is elsewher
// (as the whole account is deleted and the onChange event never
// fires).
this.report("Account-Keep", account.serviceId);
}
}
}
}
MetricsService.prototype._getValueAndTypeForStorage =
function MS__getValueAndTypeForStorage(aValue) {
var value, type = typeof(aValue);
switch (type) {
case "undefined":
value = null;
break;
case "string":
value = aValue;
break;
case "boolean":
case "number":
value = aValue.toString();
break;
case "object":
if (aValue) {
var realValue;
// Pull a single object out of a 1-element array
if ("length" in aValue &&
aValue.length === 1 &&
aValue[0] &&
typeof(aValue[0]) == "object")
{
realValue = aValue[0];
} else {
realValue = aValue;
}
// Need to make sure the object is JSON-safe, so we actually
// do a full JSON convert here instead of .toSource()
// and fall through to return null value if it fails
try {
value = "(" + JSON.toString(realValue) + ")";
break;
} catch (ex) {
}
}
// fall through
default:
value = null;
type = "undefined";
break;
}
return [value, type];
}
MetricsService.prototype.report =
function MS_report(aKey, aValue) {
if (!this._enabled) {
return;
}
try {
var [value, type] = this._getValueAndTypeForStorage(aValue);
var stmt = this._insertEvent;
stmt.reset();
pp = stmt.params;
pp.key = aKey;
pp.value = value;
pp.type = type;
pp.time = Date.now();
stmt.step();
} catch (ex) {
}
}
MetricsService.prototype.getCurrentReport =
function MS_getCurrentReport() {
var [data, expire] = this._createReport();
return data;
}
MetricsService.prototype.reportNow =
function MS_reportNow(aKey, aValue) {
/* XXX: only here to catch any users of the old API */
this.report("old-reportNow-" + aKey, aValue);
}
MetricsService.prototype.reportCount =
function MS_reportCount(aKey) {
/* XXX: only here to catch any users of the old API */
this.report("old-reportCount-" + aKey, null);
}
MetricsService.prototype._createReport =
function MS__createReport() {
var data = [];
var baseInfo = this._getBaseInfo();
var friendCounts = this._getFriendCounts();
var now = Date.now();
var expire = 0;
if (this._enabled) {
expire = now;
var sandbox = new CU.Sandbox("about:blank");
var stmt = this._getEvents;
stmt.reset();
stmt.params.time = expire;
while (stmt.step()) {
var row = stmt.row;
var entry = { key: row.key, time: row.time };
if (row.type == "string" || row.type == "undefined") {
entry.value = row.value;
} else {
entry.value = CU.evalInSandbox(row.value, sandbox);
}
data.push(entry);
}
}
for each (var value in friendCounts) {
var entry = {key: "Account-FriendCount",
value: value,
time: now};
data.push(entry);
}
for (let [key, value] in Iterator(baseInfo)) {
var entry = { key: key, value: value, time: now };
data.push(entry);
}
return [data, expire];
}
MetricsService.prototype._sendReport =
function MS__sendReport() {
var [data, expire] = this._createReport();
if (gApp.appBuildID == "0000000000") {
this._logger.debug("metrics packet: " + JSON.toString(data));
this._expireStore(expire);
return;
}
try {
var compressor = CC["@flock.com/compress-content;1"]
.createInstance(CI.flockICompressContent);
var compressedData = compressor.compressString(JSON.toString(data));
var xhr = CC["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(CI.nsIXMLHttpRequest);
var self = this;
xhr.onload = function MS__sendReportOnLoad(aEvent) {
self._onLoad(aEvent, expire);
};
xhr.onerror = function MS__sendReportOnError(aEvent) {
self._onError(aEvent);
};
xhr.backgroundRequest = true;
xhr.open("POST", LOGGING_URL);
xhr.send(compressedData);
} catch (ex) {
this._onError(null);
}
}
MetricsService.prototype._onLoad =
function MS__onLoad(aEvent, aExpire) {
var xhr = aEvent.target;
if (xhr.status == HTTP_CODE_OK) {
this._expireStore(aExpire);
}
}
MetricsService.prototype._onError =
function MS__onError(aEvent) {
// Some error happened while sending, don't clear the data
}
var gComponentsArray = [MetricsService];
var NSGetModule = FlockXPCOMUtils.generateNSGetModule(MS_CLASSNAME,
gComponentsArray);